package com.core.managers;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaValidator;

import com.model.ActionBarItem;
import com.model.ActionScript;
import com.model.KeyValue;
import com.model.MenuItem;
import com.model.TabSheetItem;
import com.model.UserContextName;
import com.model.defaults.ModelDefaultItems;
import com.model.project.ProjectItem;
import com.model.project.ProjectTask;
import com.model.project.TeamMember;
import com.model.project.TeamMemberCategory;
import com.model.project.Version;
import com.model.project.attributes.TaskComponent;
import com.model.project.attributes.TaskPriority;
import com.model.project.attributes.TaskResolution;
import com.model.project.attributes.TaskStatus;
import com.model.project.attributes.TaskType;
import com.model.report.Report;
import com.model.report.ReportColumn;
import com.model.user.User;
import com.model.user.UserCategory;
import com.model.user.UserGroup;
import com.model.user.UserRole;

public class SessionFactoryManager {

	public static final String           DB_DRIVER                = "com.mysql.jdbc.Driver";
	public static final String           DB_URL                   = "jdbc:mysql://localhost:3306/tasktracker";
	public static final String           DB_USER                  = "root";
	public static final String           DB_PASSWORD              = "";

	private AnnotationConfiguration      annotationConfiguration_ = null;
	private SessionFactory               sessionFactory_          = null;
	private static SessionFactoryManager Instance                 = null;



	public static SessionFactoryManager sharedInstance () {

		if ( Instance == null ) {
			Instance = new SessionFactoryManager();
		}
		return Instance;
	}



	private SessionFactoryManager() {

		this.checkDB();

	}



	private void checkDB () {



		Boolean connectedToDatabase = this.connectToDatabase();
		if ( !connectedToDatabase ) {
			System.out.println("unable to connect database server");
			return;
		}

		AnnotationConfiguration annotationConfiguration = this.annotationConfiguration(false);

		boolean isSchemaValid = false;
		if ( annotationConfiguration != null ) {
			try {
				isSchemaValid = this.validateConfiguration(annotationConfiguration);
			} catch ( Exception e ) {
				isSchemaValid = false;
			}
		}

		if ( isSchemaValid ) {
			return;
		}

		boolean isSchemaCreated = this.createSchema();
		if ( !isSchemaCreated ) {
			System.out.println("unable to update database schema");
			return;
		}

		ModelDefaultItems.createDefaults(this);

	}



	public PersistentClass annotatedClassByName ( String className ) {

		AnnotationConfiguration annotationConfiguration = this.annotationConfiguration(false);
		if ( annotationConfiguration == null ) {
			return null;
		}

		return annotationConfiguration.getClassMapping(className);
	}



	public String annotatedClassTableName ( Class <?> annotatedClass ) {

		AnnotationConfiguration annotationConfiguration = this.annotationConfiguration(false);
		if ( annotationConfiguration == null ) {
			return null;
		}

		String result = null;
		try {
			PersistentClass persistentClass = annotationConfiguration.getClassMapping(annotatedClass.getCanonicalName());
			if ( persistentClass != null ) {
				result = persistentClass.getTable().getQuotedName();
			}
		} catch ( Exception e ) {
		}
		return result;

	}



	private AnnotationConfiguration annotationConfiguration ( Boolean reCreate ) {

		if ( reCreate ) {
			annotationConfiguration_ = null;
		}
		if ( annotationConfiguration_ == null ) {
			try {
				annotationConfiguration_ = new AnnotationConfiguration();
				annotationConfiguration_.addAnnotatedClass(ActionBarItem.class);
				annotationConfiguration_.addAnnotatedClass(ActionScript.class);
				annotationConfiguration_.addAnnotatedClass(KeyValue.class);
				annotationConfiguration_.addAnnotatedClass(MenuItem.class);
				annotationConfiguration_.addAnnotatedClass(ProjectItem.class);
				annotationConfiguration_.addAnnotatedClass(ProjectTask.class);
				annotationConfiguration_.addAnnotatedClass(Report.class);
				annotationConfiguration_.addAnnotatedClass(ReportColumn.class);
				annotationConfiguration_.addAnnotatedClass(TabSheetItem.class);
				annotationConfiguration_.addAnnotatedClass(TaskComponent.class);
				annotationConfiguration_.addAnnotatedClass(TaskPriority.class);
				annotationConfiguration_.addAnnotatedClass(TaskResolution.class);
				annotationConfiguration_.addAnnotatedClass(TaskStatus.class);
				annotationConfiguration_.addAnnotatedClass(TaskType.class);
				annotationConfiguration_.addAnnotatedClass(User.class);
				annotationConfiguration_.addAnnotatedClass(UserCategory.class);
				annotationConfiguration_.addAnnotatedClass(UserContextName.class);
				annotationConfiguration_.addAnnotatedClass(UserGroup.class);
				annotationConfiguration_.addAnnotatedClass(UserRole.class);
				annotationConfiguration_.addAnnotatedClass(Version.class);
				annotationConfiguration_.addAnnotatedClass(TeamMemberCategory.class);
				annotationConfiguration_.addAnnotatedClass(TeamMember.class);

				annotationConfiguration_.configure("hibernate.cfg.xml");

			} catch ( Exception e ) {
				e.printStackTrace();
			}
		}
		return annotationConfiguration_;

	}



	private Boolean connectToDatabase () {

		Boolean result = true;

		try {
			Class.forName(DB_DRIVER);
			try {
				Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
				connection.close();
			} catch ( SQLException sqlException ) {
				result = false;

			}
		} catch ( ClassNotFoundException classNotFoundException ) {
			result = false;
		}
		return result;
	}



	private SessionFactory sessionFactory () {

		if ( sessionFactory_ != null ) {
			return sessionFactory_;
		}
		AnnotationConfiguration annotationConfiguration = this.annotationConfiguration(false);
		if ( annotationConfiguration == null ) {
			return null;
		}

		try {
			sessionFactory_ = annotationConfiguration.buildSessionFactory();
		} catch ( HibernateException e ) {
			e.printStackTrace();
		}

		return sessionFactory_;
	}



	private Boolean validateConfiguration ( AnnotationConfiguration annotationConfiguration ) {

		if ( annotationConfiguration == null ) {
			return false;
		}

		Boolean result = true;
		try {
			SchemaValidator schemaValidator = new SchemaValidator(annotationConfiguration);
			schemaValidator.validate();
		} catch ( HibernateException hibernateException ) {
			result = false;
		}

		return result;
	}



	private Boolean createSchema () {

		Boolean result = true;
		try {
			AnnotationConfiguration annotationConfiguration = this.annotationConfiguration(true);
			new SchemaExport(annotationConfiguration).create(true, true);
		} catch ( Exception exception ) {
			annotationConfiguration_ = null;
			result = false;
		}
		return result;
	}



	public Session openSession () {

		SessionFactory sessionFactory = this.sessionFactory();
		if ( sessionFactory == null ) {
			return null;
		}
		return sessionFactory.openSession();
	}


}
